package cn.bbstone.pisces2.server.handler;

import cn.bbstone.pisces2.comm.BFileCmd;
import cn.bbstone.pisces2.comm.Const;
import cn.bbstone.pisces2.proto.req.ReqFile;
import cn.bbstone.pisces2.proto.rsp.RspFileData;
import cn.bbstone.pisces2.server.cache.FileDataCacheItem;
import cn.bbstone.pisces2.server.cache.ServerCache;
import cn.bbstone.pisces2.server.util.MsgUtil;
import cn.bbstone.pisces2.util.CipherUtil;
import io.netty.buffer.ByteBuf;
import io.netty.channel.ChannelHandlerContext;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.IOException;

public class ReqListDataHandler implements ServerHandler {
    private static Logger log = LoggerFactory.getLogger(ReqListDataHandler.class);

    public ReqListDataHandler() {
    }

    @Override
    public void handle(ChannelHandlerContext ctx, ReqFile reqFile) {
        try {
            Byte msgType = reqFile.getMsgType();
            long fileNo = reqFile.getFileNo();
            log.debug("msgType: {}, fileNo: {}", msgType, fileNo);
            // TODO remember to close the FileInputStream after all chunks sent
            FileDataCacheItem fileDataCacheItem = ServerCache.get(fileNo);
            // skip to current read location of the fileInputStream
            long nextReadPos = fileDataCacheItem.getNextReadPos();
            FileInputStream fileInputStream = fileDataCacheItem.getFileInputStream();
            fileInputStream.skip(nextReadPos);
            // calculate chunkSize
            long fileSize = fileDataCacheItem.getFileSize();
            int chunkSize = (int) Math.min(Const.DEFAULT_CHUNK_SIZE, (fileSize - nextReadPos));
            log.debug("current pos: {}, will write {} bytes to channel.", nextReadPos, chunkSize);
            // fill payload
            byte[] chunkData = new byte[chunkSize];
            fileInputStream.read(chunkData, 0, chunkSize);
//            log.info("\t chunkData.length: {}, chunkSize: {}, chunkData: {}", chunkData.length, chunkSize, chunkData);
            //
            int chunks = fileDataCacheItem.getChunks();
            // update cache
            int chunkNo = fileDataCacheItem.getChunkNo() + 1;
            fileDataCacheItem.setChunkNo(chunkNo);
            //
            nextReadPos += chunkData.length;
            fileDataCacheItem.setNextReadPos(nextReadPos);
            //
            fileDataCacheItem.setChunkSize(chunkSize);
            log.debug("nextReadPos: {}, chunks: {}, chunkNo: {}, chunkSize: {}", nextReadPos, chunks, fileDataCacheItem.getChunkNo(), chunkSize);
            log.info("send total progress: {}/{}, index progress: {}/{}, fileSize: {} B. path: {}",
                    reqFile.getFileNo(), ServerCache.getSpCount(), chunkNo, chunks, fileDataCacheItem.getFileSize(), fileDataCacheItem.getFileAbsPath());
            // ----------------------------------------- send file data
            // build List chunk Rsp
            RspFileData rspFileData = new RspFileData();
            rspFileData.setMsgType(BFileCmd.RSP_LIST_DATA);
            rspFileData.setMsgId(reqFile.getMsgId());
            rspFileData.setReqTs(reqFile.getReqTs());
            rspFileData.setRspTs(System.currentTimeMillis());
            rspFileData.setFileNo(reqFile.getFileNo());
            rspFileData.setFileSize(0L); // only INFO has fileSize value
            rspFileData.setChunkNo(chunkNo);//
            rspFileData.setBodyLen(chunkData.length);
//        rspFileData.setBodyData(BByteUtil.convertLatin1ToUTF8(chunkData));
            rspFileData.setBodyData(chunkData);
            // set body checksum
            String bodyChecksum = CipherUtil.md5(chunkData);
            rspFileData.setChecksum(bodyChecksum);
            // build ByteBuf
            ByteBuf rsp = MsgUtil.buildRsp(rspFileData);
            log.debug("rsp.readableBytes: {}", rsp.readableBytes());
            // send data
            ctx.writeAndFlush(rsp);
        } catch (IOException e) {
            log.error("handle LIST DATA REQ error.", e);
        }
    }

}
